#include "SalesmanMainWindow.h"
#include "ui_SalesmanMainWindow.h"

#include "SelectionStrategyFactory.h"
#include "TournamentSelectionStrategy.h"
#include "Chromosome.h"


#include <QMessageBox>
#include <QFileDialog>
#include <QDebug>

SalesmanMainWindow::SalesmanMainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::SalesmanMainWindow)
{
    ui->setupUi(this);
    salEnv = NULL;
}

SalesmanMainWindow::~SalesmanMainWindow()
{
    delete ui;
    if(salEnv)
    {
        delete salEnv;
        salEnv = NULL;
    }
}

void SalesmanMainWindow::startSimulation()
{
    qDebug() << "SalesmanMainWindow::startSimulation()";

    if(salEnv && salEnv->isRunning())
    {
        qDebug() << "already running";
        ui->statusbar->showMessage(tr("Already running"), 3000);
        return;
    }

    ui->statusbar->clearMessage();

    SalesmanData salesmanData = ui->board->getData();
    if(salesmanData.size() < 3)
    {
        ui->statusbar->showMessage(tr("Mimal number of cities is 3"), 3000);
        return;
    }

    int popSize = ui->spbPopSize->value();
    int selection = Tournament;
    bool adjustFit = false;//true;
    double crossProb = ui->spbCrossProb->value();
    double mutProb = ui->spbMutProb->value();
    int generationLimit = ui->spbGenerationLimit->value();
    int tournamentSize = ui->spbTournamenSize->value();
    bool replaceWorst = true;
    int addFresh = 4;
    int eliminateDuplicates = ui->cbReplaceDupl->currentIndex();
    bool greedyStart = ui->cbGreedyStart->isChecked();//false;

    QString str("");


    SelectionStrategy* selectionStrategy = SelectionStrategyFactory::getStrategy(selection);
    if(selection == Tournament)
        dynamic_cast<TournamentSelectionStrategy*>(selectionStrategy)->setSize(tournamentSize);

    if(!salEnv)
    {
        salEnv = new SalesmanEnvironment(popSize, salesmanData, greedyStart);
    }

    //salEnv = new SalesmanEnvironment(popSize, salesmanData, greedyStart);
    salEnv->setMaxGenerationsCount(generationLimit);
    salEnv->setSelectionStrategy(selectionStrategy);
    salEnv->setAdjustFitness(adjustFit);
    salEnv->setCrossoverProb(crossProb);
    salEnv->setMutationProb(mutProb);
    salEnv->setReplaceWorstRepresentative(replaceWorst);
    salEnv->setAddFreshChromosomes(addFresh);
    salEnv->setRemoveDuplicatesMethod(eliminateDuplicates);
    salEnv->setPopulationSize(popSize);
    salEnv->setGreedyStart(greedyStart);
    salEnv->setSalesmanData(salesmanData);
    salEnv->setEmitFrequency(generationLimit/10);
    //salEnv->setMinimizeFitness();

    qRegisterMetaType<QVariant>("QVariant");
    connect(salEnv,
            SIGNAL(betterChromosomeFound(QVariant)),
            ui->board,
            SLOT(setCityPath(QVariant)));

    connect(salEnv,
            SIGNAL(simulationInfo(int,int,double,double,double,double)),
            this,
            SLOT(updateSimulationInfo(int,int,double,double,double,double)));

    connect(salEnv, SIGNAL(finished()),
            this, SLOT(onSimulationFinished()));

    ui->pbarProgress->setMaximum(generationLimit);

    salEnv->start();//startSimulation();


}

void SalesmanMainWindow::updateSimulationInfo(int popSize, int age, double bestFit,
                        double worstFit, double sumFit, double workTime)
{
    //qDebug() << "SalesmanMainWindow::updateSimulationInfo";

    ui->tbGenCount->display(age);
    ui->pbarProgress->setValue(age);

    ui->tbGenCount->repaint();
    if(bestFit == 0)
         ui->tbBestFit->clear();
    else
        ui->tbBestFit->setText(QString::number(-bestFit));
    if(worstFit == 0)
        ui->tbWorstFit->clear();
    else
        ui->tbWorstFit->setText(QString::number(-worstFit));
    if(sumFit == 0)
        ui->tbSumFit->clear();
    else
        ui->tbSumFit->setText(QString::number(-sumFit));

    if(popSize == 0 || sumFit == 0)
        ui->tbAvFit->clear();
    else
        ui->tbAvFit->setText(QString::number(-sumFit/popSize));

    if(workTime == 0)
    {
        ui->statusbar->clearMessage();
        ui->tbTime->clear();
        ui->tbGenPerS->clear();
    }
    else
    {
        ui->tbTime->setText(QString::number(workTime));
        ui->tbGenPerS->setText(QString::number(age/workTime));
    }

}

void SalesmanMainWindow::loadFromFile()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"),
                                                     "./",
                                                     tr("XML (*.xml)"));
    qDebug() << "SalesmanMainWindow::loadFromFile fileName: " << fileName;

    if(fileName.isEmpty())
        return;

    updateSimulationInfo();
    SalesmanData data("", fileName);
    ui->board->setData(data);
    ui->statusbar->showMessage(tr("File loaded"), 5000);
}

void SalesmanMainWindow::saveToFile()
{
    QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),
                               "./cityset.xml",
                               tr("XML (*.xml)"));

    qDebug() << "SalesmanMainWindow::saveToFile fileName: " << fileName;

    if(fileName.isEmpty())
        return;

    ui->board->getData().saveToFile("", fileName);
    ui->statusbar->showMessage(tr("File saved"), 5000);
}

void SalesmanMainWindow::changeEvent(QEvent *e)
{
    QMainWindow::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);
        break;
    default:
        break;
    }
}

void SalesmanMainWindow::onSimulationFinished()
{
    qDebug() << *salEnv->getSolution();

    qDebug() << salEnv->getStatisticsString();

    ui->board->setCityPath(salEnv->getSolution()->data());

    ui->statusbar->showMessage(salEnv->getSolution()->toString());
}

void SalesmanMainWindow::stopSimulation()
{
    qDebug() << "SalesmanMainWindow::stopSimulation()";
    if(salEnv && salEnv->isRunning())
    {
        salEnv->stop();
        qDebug() << "stop";
        ui->statusbar->showMessage(tr("Stop"), 3000);
    }
}
